﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Text;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.Configuration;

namespace Cosoware.Web.Themes
{
    /// <summary>
    /// Manages themes. Allows to set a website theme and to    enumerate available themes.
    /// </summary>
    public class ThemeManagementModule : IHttpModule
    {
        /// <summary>
        /// The session key used to store session.
        /// </summary>
        private const string _sessionKey = "ThemeManagementModule_ThemeName";

        /// <summary>
        /// Gets the current session from context.
        /// </summary>
        /// <value>The current session.</value>
        private static HttpSessionState Session
        {
            get
            {
                try
                {
                    return HttpContext.Current.Session;
                }
                catch (NullReferenceException e)
                {
                    throw new InvalidOperationException("HttpContext is invalid.", e);
                }
            }
        }

        /// <summary>
        /// Gets or sets the name of the current theme.
        /// </summary>
        /// <value>The name of the current theme.</value>
        public static string CurrentTheme
        {
            get
            {
                return (Session[_sessionKey] != null) ? Session[_sessionKey].ToString() : String.Empty;
            }
            set
            {
                if (!IsThemeSupported(value))
                    throw new InvalidOperationException(String.Format("Theme '{0}' not supported.", value));
                Session[_sessionKey] = value;
            }
        }

        /// <summary>
        /// Sets the currently requested page theme.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private static void SetTheme(object sender, EventArgs e)
        {
            if (!String.IsNullOrEmpty(CurrentTheme))
                ((Page)sender).Theme = CurrentTheme;
        }

        /// <summary>
        /// Determines whether theme is supported.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns>
        /// 	<c>true</c> if theme is supported; otherwise, <c>false</c>.
        /// </returns>
        private static bool IsThemeSupported(string name)
        {
            foreach (var theme in Themes)
            {
                if (theme == name)
                    return true;
            }
            return false;
        }

        /// <summary>
        /// Gets the list of an installed themes.
        /// </summary>
        /// <value>The list of an installed themes.</value>
        public static IEnumerable<string> Themes
        {
            get
            {
                bool flag;
                if (Boolean.TryParse(WebConfigurationManager.AppSettings["UseSystemFileWatcherInThemeManager"], out flag))
                    ThemeListHelper.WatcherEnabled = flag;
                return ThemeListHelper.Themes;
            }
        }

        /// <summary>
        /// The current http application
        /// </summary>
        private HttpApplication _application;

        /// <summary>
        /// Initializes a module and prepares it to handle requests.
        /// </summary>
        /// <param name="application">The current application.</param>
        public void Init(HttpApplication application)
        {
            _application = application;
            _application.PreRequestHandlerExecute += new EventHandler(Subscribe);
            _application.PostRequestHandlerExecute += new EventHandler(Unsubscribe);
        }

        /// <summary>
        /// Subscribes to the current page PreInit event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void Subscribe(object sender, EventArgs e)
        {
            Page page = _application.Context.Handler as Page;
            if (page != null)
                page.PreInit += new EventHandler(SetTheme);
        }

        /// <summary>
        /// Unsubscribes to the current page PreInit event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void Unsubscribe(object sender, EventArgs e)
        {
            Page page = _application.Context.Handler as Page;
            if (page != null)
                page.PreInit -= new EventHandler(SetTheme);
        }

        /// <summary>
        /// Disposes of the resources.
        /// </summary>
        public void Dispose()
        {
        }
    }
}
